<?php

namespace App\Http\Controllers\Admin\Finance;

use App\Exceptions\AppException;
use App\Http\Controllers\Controller;
use App\Models\airline\base\FlightModel as BaseFlightModel;
use App\Models\airline\base\RouteModel;
use App\Models\base\CurrencyModel;
use App\Models\base\SubjectModel;
use App\Models\CustomerChargeModel;
use App\Models\FlightItemModel;
use App\Models\FlightModel;
use App\Models\OrderModel;
use App\Models\RecBillIdsModel;
use App\Models\RecBillModel;
use App\Models\service\CompensateModel;
use App\Models\TakeOrderModel;
use App\Models\TakeOrderRecModel;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;

class Receivable extends Controller
{
    
    public function take_orders(Request $request) {
        $page = $request->input('page', 1);
        $limit = $request->input('limit', 10);


        $query = (function() use ($request) {
            $des_country_id = $request->input('countrie_id', 0);
            $customer_name = $request->input('customer_name', '');
            $airline_id = $request->input('airline_id', '');
            $flight_number = $request->input('flight_number', '');
            $status = $request->input('status', '');
            $sn = $request->input('sn', []);
            $order_sn = $request->input('order_sn', []);
            $start_port_id = $request->input('start_port_id', 0);//始发地港口
    
            $query = TakeOrderModel::query();
    
            if($des_country_id) {
                $query->whereIn('flight_id', function($query) use ($des_country_id){
                    $query->select('flight_id')
                        ->from((new FlightItemModel())->getTable())
                        ->where('destination_id', $des_country_id);
                });
            }

            if($start_port_id){
                $query->whereIn('flight_id', function($query) use ($start_port_id){
                    $query->select('id')
                        ->from((new FlightModel())->getTable())
                        ->where('start_port_id', $start_port_id);
                });
            }
    
            if($customer_name) {
                $query->whereHas('customer', function($query) use ($customer_name) {
                    $query->where('name', 'like', '%'.$customer_name.'%');
                });
            }
    
            if($airline_id) {
                $query->whereIn('flight_id', function($query) use ($airline_id){
                    $query->select('flight_id')
                        ->from((new FlightItemModel())->getTable())
                        ->where('route_id', $airline_id);
                });
            }
    
            if($flight_number) {
                $query->whereIn('flight_id', function($query) use ($flight_number){
                    $query->select('flight_id')
                        ->from((new FlightItemModel())->getTable())
                        ->whereIn('airline_flight_id', function($query) use ($flight_number){
                            $query->select('id')
                                ->from((new BaseFlightModel())->getTable())
                                ->where('flight_number', $flight_number);
                        });
                });
            }
    
            if($status) $query->where('status', $status);

            if($sn && is_array($sn)) {
                $query->whereIn('sn', $sn);
            }

            if($order_sn && is_array($order_sn)) {
                $query->whereIn('id', function($query) use ($order_sn) {
                    $query->select('take_order_id')
                        ->from((new OrderModel())->getTable())
                        ->whereIn('sn', $order_sn);
                });
            }

            return $query;
        })();

        $total = $query->count('id');
        $items = $query
            ->with(['recs'])
            ->withCount('orders')
            ->offset(($page-1) * $limit)
            ->limit($limit)
            ->orderBy('id', 'desc')
            ->get();

        $list = $items->map(function ($item) {
            $split_order_count = $item->orders->sum('split_order_addr_count'); //分单数
            $big_pkgs = $item->orders->sum('big_pkgs'); // 大包数
            $pre_volume = $item->orders->sum('pre_volume');  //预报体积
            $storage_weight = $item->orders->sum('storage_weight'); //入库重

            $flight_lines = $item->flight->items ?? null; //航班运力信息
            $start_port = $flight_lines?->first()->start_port?->name ?? ''; //始发港
            $des_country = $flight_lines?->first()->destination->name ?? ''; //目的地国家

            $route_ids = $flight_lines?->pluck('route_id') ?? [];
            $lines = RouteModel::whereIn('id', $route_ids)->pluck('name')->toArray(); //航线

            $airline_flight_ids = $flight_lines?->pluck('airline_flight_id') ?? [];
            $flight_no = BaseFlightModel::whereIn('id', $airline_flight_ids)->pluck('flight_number')->toArray(); //航班号

            $total = [];
            foreach($item->recs as $rec) {
                if(!isset($total[$rec->currency])) {
                    $total[$rec->symbol] = $rec->amount;
                } else {
                    $total[$rec->symbol] += $rec->amount;
                }
            }

            $result = implode(', ', array_map(function($key, $value) {
                return "{$key}{$value}";
            }, array_keys($total), $total));

            return [
                'id' => $item->id,
                'customer_name' => $item->customer->name ?? '',
                'customer_sn' => $item->customer->sn ?? '',
                'sn' => $item->sn,
                'big_pkgs' => $big_pkgs,
                'split_order_count' => $split_order_count,
                'order_count' => $item->orders_count,
                'storage_weight' => $storage_weight,
                'pre_volume' => $pre_volume,
                'reality_weight' => $item->reality_weight,
                'total_rec' => $result,
                'account_status' => $item->rec_bill_status == 1 ? '未出账' : '已出账',
                'rec_status' => '待收款',
                'start_port' => $start_port,
                'des_country' => $des_country,
                'flight_route' => implode(',', $lines),
                'flight_no' => implode(' ', $flight_no),
                'cargo_status' => TakeOrderModel::STATUS_MAPS[$item->status],
                'take_off_time' => $item->flight->take_off_time ?? '',
                'cargo_time' => '-',
                'settle_time' => $item->settle_time,
                'volume_weight' => $item->volume_weight,
                'rec_p' => TakeOrderModel::$rec_p[$item->rec_p] ?? '',
                'fee_weight' => $item->fee_weight,
            ];
        });

        return $this->success(['list' => $list, 'total' => $total]);
    }

    //确认结算重量
    public function confirm(Request $request, $id) {
        $take_order = TakeOrderModel::find($id);
        if(!$take_order) {
            return $this->error('提单不存在');
        }

        $weight = $request->input('weight');
        if(!$weight) {
            return $this->error('结算重量不能为空');
        }

        DB::transaction(function() use ($take_order, $weight){
            $take_order->fee_weight = $weight;
            $take_order->save();

            TakeOrderRecModel::where('take_order_id', $take_order->id)
                ->where('type', TakeOrderRecModel::TYPE_FLIGHT)
                ->delete();

            $customer = $take_order->orders->first()->customer;
            if(!$customer) {
                throw new AppException('提单客户错误');
            }
            if($customer->charges->count() == 0) {
                throw new AppException('客户未设置报价');
            }

            $charge = CustomerChargeModel::where('customer_id', $customer->id)
                ->where('end', '>=', $weight)
                ->orderBy('end', 'asc')
                ->first();
            if(!$charge) {
                $charge = CustomerChargeModel::where('customer_id', $customer->id)
                    ->orderBy('end', 'desc')
                    ->first();
            }

            if(!$charge) {
                throw new AppException('客户未设置报价');
            }

            $currency = CurrencyModel::where('short_code', $customer->charge_currency)->first();
            if(!$currency) {
                throw new AppException('客户收费币种错误');
            }

            TakeOrderRecModel::create([
                'take_order_id' => $take_order->id,
                'currency' => $customer->charge_currency,
                'symbol' => $currency->symbol,
                'type' => TakeOrderRecModel::TYPE_FLIGHT,
                'amount' => $weight * $charge->price,
                'sys_amount' => $weight * $charge->price,
                'is_sys' => 1,
            ]);

        });

        return $this->success();
    }

    //应收明细
    public function rec_info(Request $request) {
        $id = $request->input('id');
        $items = TakeOrderRecModel::where('take_order_id', $id)->get();

        $list = $items->map(function($item) {
            $name = TakeOrderRecModel::TYPE_MAPS[$item->type] ?? '';
            if($item->type == TakeOrderRecModel::TYPE_OTHER) {
                $subject = SubjectModel::find($item->subject_id);
                $name = '补录' . ($subject->name ?? '');
            }

            $currency = CurrencyModel::where('short_code', $item->currency)->first();

            return [
                'id' => $item->id,
                'name' => $name,
                'currency' => $item->currency,
                'sys_amount' => $item->sys_amount,
                'amount' => $item->amount,
                'symbol' => $item->symbol,
                'create_user' => $item->create_admin->staff->name ?? '系统生成',
                'created_at' => $item->created_at->toDateTimeString(),
                'remark' => $item->remark,
                'subject_id' => $item->subject_id,
                'currency_id' => $currency->id ?? 0,
                'is_sys' => $item->is_sys
            ];
        });

        $collect = [];
        foreach($list as $item) {
            if(isset($collect[$item['symbol']])) {
                $collect[$item['symbol']] += $item['amount'];
            } else {
                $collect[$item['symbol']] = $item['amount'];
            }
        }

        $result = '';
        foreach ($collect as $symbol => $value) {
            if (!empty($result)) {
                $result .= ", ";
            }
            $result .= $symbol . $value;
        }

        return $this->success([
            'list' => $list,
            'total' => $result
        ]);

    }

    //补录费用
    public function add_rec(Request $request) {
        $ids = $request->input('ids');
        if(!is_array($ids) || empty($ids)) {
            return $this->success();
        }

        $items = $request->input('items');
        if(!is_array($items) || empty($items)) {
            return $this->error('请填写补录费用');
        }

        foreach($items as $item) {
            $validator = Validator::make($item, [
                'subject_id' => 'required|exists:t_base_subject,id',
                'currency_id' => 'required|exists:t_base_currency,id',
                'amount' => 'required|numeric|gt:0',
            ], [
                'subject_id.required' => '费用科目不能为空',
                'subject_id.exists' => '费用科目错误',
                'currency_id.required' => '币种不能为空',
                'currency_id.exists' => '币种错误',
                'amount.required' => '金额不能为空',
                'amount.numeric' => '金额必须为数字',
                'amount.gt' => '金额必须大于0'
            ]);
            if ($validator->fails()) {
                $err = $validator->errors()->first();
                return $this->error($err);
            }
        }

        $auth = $request->get('auth');

        DB::transaction(function() use ($ids, $auth, $items) {
            foreach($ids as $id) {
                $take_order = TakeOrderModel::find($id);
                if(!$take_order) {
                    continue;
                }

                foreach($items as $item) {
                    $currency = CurrencyModel::find($item['currency_id']);
                    if(!$currency) {
                        return $this->error('币种错误');
                    }
                    TakeOrderRecModel::create([
                        'take_order_id' => $take_order->id,
                        'currency' => $currency->short_code,
                        'symbol' => $currency->symbol,
                        'type' => TakeOrderRecModel::TYPE_OTHER,
                        'subject_id' => $item['subject_id'],
                        'amount' => $item['amount'],
                        'remark' => $item['remark'] ?? '',
                        'created_admin_id' => $auth->id
                    ]);
                }
            }
        });

        return $this->success();
    }

    //修改费用
    public function update_rec(Request $request, $id) {
        $rec = TakeOrderRecModel::find($id);
        if(!$rec) {
            return $this->success();
        }

        $rec->amount = $request->input('amount');
        $rec->remark = $request->input('remark');
        $rec->save();
        return $this->success();
    }

    //删除费用
    public function del_rec($id) {
        $rec = TakeOrderRecModel::find($id);
        if(!$rec) {
            return $this->success();
        }

        if($rec->type != TakeOrderRecModel::TYPE_OTHER) {
            return $this->error('非补录费用不能删除');
        }

        TakeOrderRecModel::destroy($id);
        return $this->success();
    }

    //生成账单
    public function create_bill(Request $request) {
        $ids = $request->input('ids');

        $take_orders = TakeOrderModel::whereIn('id', $ids)->get();

        $customer_bill = [];
        foreach($take_orders as $take_order) {
            if($take_order->rec_bill_status != 1) {
                return $this->error($take_order->sn . '已出账,请勿重复出账');
            }
            //应收
            $recs = TakeOrderRecModel::where('take_order_id', $take_order->id)->get();
            foreach($recs as $rec) {
                $key = $take_order->customer_id . '_' . $rec->currency;
                if(isset($customer_bill[$key])) {
                    $customer_bill[$key]['rec_amount'] += $rec->amount;
                    $customer_bill[$key]['rec_take_orders']++;
                } else {
                    $customer_bill[$key] = [
                        'key' => $key,
                        'customer_name' => $take_order->customer->name ?? '',
                        'customer_sn' => $take_order->customer->sn ?? '',
                        'currency' => $rec->currency,

                        'rec_take_orders' => 1,
                        'rec_amount' => $rec->amount,

                        'comp_take_orders' => 0,
                        'comp_amount' => 0,
                    ];
                }
            }

            //赔偿
            $comps = CompensateModel::where('take_order_id', $take_order->id)
                ->where('status', 4)->get();
            foreach($comps as $comp) {
                $key = $take_order->customer_id . '_' . $comp->actual_currency->short_code;
                if(isset($customer_bill[$key])) {
                    $customer_bill[$key]['comp_amount'] += $comp->actual_amount;
                    $customer_bill[$key]['comp_take_orders']++;
                } else {
                    $customer_bill[$key] = [
                        'key' => $key,
                        'customer_name' => $take_order->customer->name ?? '',
                        'customer_sn' => $take_order->customer->sn ?? '',
                        'currency' => $comp->actual_currency->short_code,

                        'rec_take_orders' => 0,
                        'rec_amount' => 0,

                        'comp_take_orders' => 1,
                        'comp_amount' => $comp->actual_amount,
                    ];
                }
            }
        }

        $list = array_values($customer_bill);
        return $this->success($list);
    }

    //确认生成账单
    public function confirm_bill(Request $request) {
        $ids = $request->input('ids');
        if(!is_array($ids) || empty($ids)) {
            return $this->success();
        }
        $remarks = $request->input('remarks');
        if(!is_array($remarks)) {
            $remarks = [];
        }

        $remarks = array_column($remarks, null, 'key');
        $start = $request->input('start');
        $end = $request->input('end');

        if(empty($start) || empty($end)) {
            return $this->error('请选择账单周期');
        }

        $take_orders = TakeOrderModel::whereIn('id', $ids)->get();
        $customer_bill = [];
        foreach($take_orders as $take_order) {
            if($take_order->rec_bill_status != 1) {
                return $this->error($take_order->sn . '已出账,请勿重复出账');
            }
            $take_order_id = $take_order->id;
            //应收
            $recs = TakeOrderRecModel::where('take_order_id', $take_order->id)->get();
            foreach($recs as $rec) {
                $key = $take_order->customer_id . '_' . $rec->currency;
                $remark = $remarks[$key]['remark'] ?? '';
                if(isset($customer_bill[$key])) {
                    $customer_bill[$key]['rec_amount'] += $rec->amount;
                    $customer_bill[$key]['take_order_ids'][] = $take_order_id;
                } else {
                    $customer_bill[$key] = [
                        'key' => $key,
                        'customer_id' => $take_order->customer_id,
                        'customer_name' => $take_order->customer->name,
                        'customer_sn' => $take_order->customer->sn,
                        'currency' => $rec->currency,

                        'rec_amount' => $rec->amount,

                        'comp_take_orders' => 1,
                        'comp_amount' => 0,

                        'remark' => $remark,
                        'take_order_ids' => [$take_order_id]
                    ];
                }

            }

            //赔偿
            $comps = CompensateModel::where('take_order_id', $take_order->id)
                ->where('status', 4)->get();
            foreach($comps as $comp) {
                $key = $take_order->customer_id . '_' . $comp->actual_currency->short_code;
                if(isset($customer_bill[$key])) {
                    $customer_bill[$key]['comp_amount'] += $comp->actual_amount;
                    $customer_bill[$key]['comp_take_orders']++;
                } else {
                    $customer_bill[$key] = [
                        'key' => $key,
                        'customer_name' => $take_order->customer->name ?? '',
                        'customer_sn' => $take_order->customer->sn ?? '',
                        'currency' => $comp->actual_currency->short_code,

                        'rec_take_orders' => 0,
                        'rec_amount' => 0,

                        'comp_take_orders' => 1,
                        'comp_amount' => $comp->actual_amount,
                    ];
                }
            }
        }

        $auth = $request->get('auth');
        DB::transaction(function() use ($customer_bill, $start, $end, $auth, $take_orders){
            foreach($customer_bill as $bill) {
                $rec_bill = new RecBillModel();
                $rec_bill->customer_id = $bill['customer_id'];
                $rec_bill->currency = $bill['currency'];
                $rec_bill->amount = $bill['rec_amount'] - $bill['comp_amount'];
                $rec_bill->comp_amount = $bill['comp_amount'];
                $rec_bill->remark = $bill['remark'] ?? '';
                $rec_bill->start = $start;
                $rec_bill->end = $end;
                $rec_bill->take_order_count = $take_orders->count();
                $rec_bill->created_admin_id = $auth->id;
                $rec_bill->save();
                $rec_bill->sn = 'ZD' . date('Ymd') . $rec_bill->id;
                $rec_bill->save();

                foreach(array_unique($take_orders->pluck('id')->toArray()) as $take_order_id) {
                    $ids = new RecBillIdsModel();
                    $ids->rec_bill_id = $rec_bill->id;
                    $ids->take_order_id = $take_order_id;
                    $ids->save();
                }
            }

            //提单出账状态改为已出账
            TakeOrderModel::whereIn('id', $take_orders->pluck('id'))->update([
                'rec_bill_status' => 2
            ]);



        });

        return $this->success();

    }

}
